﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Audio;

namespace Project1
{
    public class Turret 
    {
        #region Member Variables

        /// <summary>
        /// A handle to our game
        /// </summary>
        TurretGame mGame;

        /// <summary>
        /// The turret model
        /// </summary>
        Model mModel;

        /// <summary>
        /// The index of the Turret in the model
        /// </summary>
        private int mTurretPivot;

        /// <summary>
        /// The index of the elevation control in the model
        /// </summary>
        private int mElevation;

        /// <summary>
        /// The index of the barrel for the model
        /// </summary>
        private int mBarrel;

        /// <summary>
        /// The elevation angle of the barrel
        /// </summary>
        private float mElevationAngle = 0;

        /// <summary>
        /// The rate at which we rotate our barrel
        /// </summary>
        private float mElevationRate = 0;

        /// <summary>
        /// The angle the barrel is pointing
        /// </summary>
        private int mRotationAngle = 0;

        /// <summary>
        /// The rate at which we turn our turret.
        /// </summary>
        private float mRotationRate = 0;

        /// <summary>
        /// The translation for the barrel upon it being fired
        /// </summary>
        private float mBarrelMovement = 0;

        /// <summary>
        /// An instance of our laser fire class
        /// </summary>
        private LaserFire mLaserFire;

        private Vector3 mLaserLocation = new Vector3(-360, 146, 10);

        #endregion

        #region Properties

        public Matrix Transform
        {
            get
            {
                return Matrix.CreateRotationZ(MathHelper.ToRadians(-mElevationAngle)) *
                    Matrix.CreateRotationY(MathHelper.ToRadians(mRotationAngle));
                       
            }
        }

        public LaserFire pLaserFire
            { get { return mLaserFire; } }

        public Model TurretModel { get { return mModel; } }


        public float Rotation{ get { return MathHelper.ToRadians(mRotationAngle); } }

        public float RotationRate{ get { return mRotationRate; } set{ mRotationRate = value; } }

        public float ElevationRate { get { return mElevationRate; } set { mElevationRate = value; } }

        #endregion

        public Turret(TurretGame aGame)
        {
            this.mGame = aGame;
            mLaserFire = new LaserFire(aGame);
        }
        /// <summary>
        /// This function is called to load content into
        /// our game
        /// </summary>
        /// <param name="aContent"></param>
        public void  LoadContent(ContentManager aContent)
        {
            mModel = aContent.Load<Model>("DeckTurrentGun");
            mElevation = mModel.Bones.IndexOf(mModel.Bones["Elevation"]);
            mTurretPivot = mModel.Bones.IndexOf(mModel.Bones["TurrentPivot"]);
            mBarrel = mModel.Bones.IndexOf(mModel.Bones["Barrel"]);
            mLaserFire.LoadContent(aContent);
        }

        /// <summary>
        /// This function is called to update this component 
        /// to the current game time
        /// </summary>
        /// <param name="aGameTime"></param>
        public void Update(GameTime aGameTime)
        {
            float lBarrelReturnTime = .01f;
            if (mBarrelMovement > 0)
            {
                mBarrelMovement = 0;
            }
            if (mBarrelMovement < 0)
            {
                mBarrelMovement += (float)(8.0 * aGameTime.ElapsedGameTime.TotalSeconds / lBarrelReturnTime);
            }

            if (mRotationRate != 0)
            {
                mRotationAngle += (int)mRotationRate;
            }

            if (mElevationRate == -1 && mElevationAngle > -45)
            {
                mElevationAngle += (int)mElevationRate;
            }
            else if (mElevationRate == 1 && mElevationAngle < 45)
            {
                mElevationAngle += (int)mElevationRate;
            }
            mLaserFire.Update(aGameTime);
        }

        /// <summary>
        /// This function is called to draw this game component
        /// </summary>
        /// <param name="aGraphics"></param>
        /// <param name="aGameTime"></param>
        public void Draw(GraphicsDeviceManager aGraphics, GameTime aGameTime)
        {
            DrawModel(aGraphics, mModel, Matrix.Identity);
            mLaserFire.Draw(aGraphics, aGameTime);
        }

        /// <summary>
        /// This function will draw the model
        /// </summary>
        /// <param name="aGraphics"></param>
        /// <param name="aModel"></param>
        /// <param name="aWorld"></param>
        private void DrawModel(GraphicsDeviceManager aGraphics, Model aModel, Matrix aWorld)
        {
            Matrix[] lTransforms = new Matrix[aModel.Bones.Count];
            aModel.CopyAbsoluteBoneTransformsTo(lTransforms);

            for (int i = 0; i < mModel.Bones.Count; i++)
            {
                if (i == mTurretPivot)
                    lTransforms[i] = Matrix.CreateRotationZ(MathHelper.ToRadians(mRotationAngle));

                else if (i == mElevation)
                    lTransforms[i] = Matrix.CreateRotationZ(MathHelper.ToRadians(-mElevationAngle));

                else if (i == mBarrel)
                    lTransforms[i] = Matrix.CreateTranslation(new Vector3(0, 0, mBarrelMovement));
                
                else
                    lTransforms[i] = Matrix.Identity;

                ModelBone lBone = mModel.Bones[i];
                if (lBone.Parent == null)
                {
                    lTransforms[i] *= lBone.Transform;
                }

                else 
                {
                    lTransforms[i] *= lBone.Transform * lTransforms[lBone.Parent.Index];
                }
            }


            foreach (ModelMesh lMesh in aModel.Meshes)
            {
                foreach (BasicEffect lEffect in lMesh.Effects)
                {
                    lEffect.EnableDefaultLighting();
                    lEffect.World = lTransforms[lMesh.ParentBone.Index] * aWorld;
                    lEffect.View = mGame.Camera.View;
                    lEffect.Projection = mGame.Camera.Projection;
                }
                lMesh.Draw();
            }
        }

        /// <summary>
        /// Fires the cannon, possibly could change ammo.
        /// </summary>
        public void FireCannon()
        {
            // If the barrel has finished recoiling
            if (mBarrelMovement == 0)
            {
                mBarrelMovement = -90.0f;
                //
                Vector3 lPosition = Vector3.Transform(mLaserLocation, Transform);
                // Need to rotate by -90 around Y because of the way LaserBlast
                // was created pointing in the z direction
                Matrix lOrientation = Matrix.CreateRotationY(MathHelper.ToRadians(-90))
                                      * Transform;
                mGame.SoundBank.PlayCue("tx0_fire1");
                mLaserFire.FireLaser(lPosition, lOrientation, 200.0f);
            }
            
        }

        public void Reset()
        {

            mElevationAngle = 0;
            mElevationRate = 0;
            mRotationAngle = 0;
            mRotationRate = 0;
            mBarrelMovement = 0;
            mLaserFire.Reset();

        }
    }
}
